﻿using System;
using System.Collections.Generic;
using System.Web;
using Jayden.Dll.Core.Extensions;
using Jayden.Dll.Web.Enums;
using Jayden.Dll.Web.Helper;
using Jayden.Dll.Web.HtmlControls.Descriptions;
using Jayden.Dll.Web.HtmlControls.Generics;
using Jayden.Dll.Web.HtmlControls.Interfaces;

namespace Jayden.Dll.Web.HtmlControls
{
	public class Form : HtmlElement, WithAction, WithMethod, WithEncType, WithName, WithTarget, WithAutoComplete, WithNoValidate
	{

		public Form() : base(FormDescription.Instance) { }

		public string Name { get { return this["name"]; } set { this["name"] = value; } }
		public string Target { get { return this["target"]; } set { this["target"] = value; } }
		public string Action { get { return this["action"]; } set { this["action"] = value; } }
		public HtmlFormMethod Method { get { return (HtmlFormMethod)Enum.Parse(typeof(HtmlInputType), GetAttribute("method", false, false, "get"), true); } set { this["method"] = (value == HtmlFormMethod.Get) ? null : value.ToString().UnCamelCase(); } }
		public string EncType { get { return this["enctype"]; } set { this["enctype"] = value; } }
		public bool AutoComplete { get { return GetAttribute("autocomplete", false, true, "on") == "on"; } set { this["autocomplete"] = value ? null : "off"; } }
		public string AcceptCharset { get { return this["accept-charset"]; } set { this["accept-charset"] = value; } }
		public bool NoValidate { get { return GetAttributeBool("novalidate"); } set { SetAttribute("novalidate", value); } }

		public Label FindLabel(HtmlElement e)
		{
			if (e != null && e.Parent != null && e.Id != null)
			{
				HtmlElement parent = e.Parent as HtmlElement;
				List<Label> labels = new List<Label>(parent.GetControls<Label>());
				if (labels.Count == 1)
				{
					// assign "for" attribute of label so it focus the target when the client click on the label
					labels[0].For = e.Id;
					return labels[0];
				}
			}
			return null;
		}

		public IEnumerable<HtmlElement> GetFormElements()
		{
			return GetElements<HtmlElement>(delegate(HtmlElement c) { if (c is Input || c is Textarea || c is Select || c is Button) return true; return false; }, null);
		}

		public T GetFormElement<T>(string id, bool assignId = true, bool assignName = true) where T : HtmlElement, WithName { return GetElementByServerId<T>(id, assignId, assignName); }
		public T GetFormElement<T>(string id, string name) where T : HtmlElement, WithName { return GetElementByServerId<T>(id, true, name); }
		public string GetFormValue(HttpContext context, WithName element)
		{
			if (element != null)
			{
				string name = element.Name;
				if (name != null)
				{
					string value = context.Request[name];
					return value;
				}
			}
			return null;
		}

	}
	public class FormDescription : HtmlElementDescription
	{
		public static readonly FormDescription Instance = new FormDescription();
		private FormDescription() : base("form") { }
		public override Type ControlType { get { return typeof(Form); } }
		public override bool IsFlowElement { get { return true; } }
		public override bool OnlyFlowContent { get { return true; } }
		public override string Description { get { return "user-submittable form."; } }
		public override bool CheckValidity(HtmlControl control)
		{
			if (base.CheckValidity(control))
			{
				Form form = control as Form;
				HtmlControl parent = control.Parent;
				while (parent != null)
				{
					if (parent is Form)
						throw new Exception("The <form> element must not contain any nested <form> elements.");
					parent = parent.Parent;
				}
				if (form.EncType == null)
					return true;
				switch (form.EncType)
				{
					case HtmlHelper.ApplicationFormUrlEncoded:
					case HtmlHelper.MultipartFormData:
					case HtmlHelper.TextPlain:
						return true;
				}
				throw new Exception(string.Format("<form> attribute 'enctype' has an invalid value : '{0}'.", form.EncType));
			}
			return false;
		}
	}
}
